package my.music.aop;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import my.music.common.result.ResultEnum;
import my.music.common.result.ResultModel;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
@Slf4j
public class ControllerLogAop {

    /**
     * 前置通知（@Before）：在目标方法调用之前调用通知
     * @param joinPoint
     */
    @Before(value = "execution (public * my.music.controller.*.*(..))")
    public void before(JoinPoint joinPoint){
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        StringBuffer params = new StringBuffer();
        for (Object arg : args) {
            params.append(arg).append(" ");
        }
        log.info(className + "#" + methodName + "【入参】: " + params.toString());
    }

    /**
     * 环绕通知（@Around）：在被通知的方法调用之前和调用之后执行自定义的方法
     * @param joinPoint
     * @return
     */
    @Around(value = "execution (public * my.music.controller.*.*(..))")
    public Object catchException(ProceedingJoinPoint joinPoint){
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        try {
            // 方法执行开始时间
            long st = System.currentTimeMillis();

            // 开始执行方法
            Object proceed = joinPoint.proceed();

            // 方法执行结束时间
            long et = System.currentTimeMillis();

            log.info(className + "#" + methodName + "【运行时长】：{} ms", et - st);
            return proceed;
        } catch (Throwable e){

            log.error(className + "#" + methodName + "【发生异常】：{}", e);
            return ResultModel.error(ResultEnum.USER_REQUEST_EXCEPTION);
        }
    }

    /**
     * 返回通知（@AfterReturning）：在目标方法成功执行之后调用通知
     * @param joinPoint
     * @param returnVal
     */
    @AfterReturning(value = "execution (public * my.music.controller.*.*(..))", returning = "returnVal")
    public void afterReturn(JoinPoint joinPoint, Object returnVal) throws JsonProcessingException {
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        log.debug(className + "#" + methodName + "【返回】: " + new ObjectMapper().writeValueAsString(returnVal));
    }
}
